package com.imagination.applet.domain.aiimage.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSException;
import com.imagination.applet.controller.api.request.AddAIImageRequest;
import com.imagination.applet.controller.api.request.cropReq;
import com.imagination.applet.domain.adapter.facechain.FaceChainAdapter;
import com.imagination.applet.domain.adapter.os.OSSAdapter;
import com.imagination.applet.domain.aiimage.model.AIImage;
import com.imagination.applet.domain.aiimage.repository.AIImageRepository;
import com.imagination.applet.domain.aiimage.service.AIImageCommandService;
import com.imagination.applet.domain.aiimage.service.AIImageQueryService;
import com.imagination.applet.domain.utils.ImagePathGenerator;
import com.imagination.applet.infrastructure.handler.ServiceException;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;

@Log4j2
@Service
@RequiredArgsConstructor(onConstructor = @__({@Autowired}))
public class AIImageQueryServiceImpl implements AIImageQueryService, AIImageCommandService {
    private final AIImageRepository aiImageRepository;
    private final OSSAdapter ossAdapter;
    private final FaceChainAdapter faceChainAdapter;
    @Override
    public List<AIImage> queryTopGeneratedImagesByChannel(String channel) {
        return aiImageRepository.queryByChannelTypeAndDelFlag(channel,"0").stream().sorted(Comparator.comparingInt(AIImage::getSort)).toList();
    }

    @Override
    public Page<AIImage> queryGeneratedImagesByChannelAndTopicPageable(String channel, String topic, Pageable pageable) {
        return aiImageRepository.queryByChannelTypeAndTopicTypeAndDelFlag(channel, topic,"0", pageable);
    }

    @Override
    public AIImage queryGeneratedImage(Long imageId) {
        Optional<AIImage> image = aiImageRepository.findById(imageId);
        if (image.isEmpty()) {
            throw new RuntimeException();
        }
        return image.get();
    }

    @Override
    public List<AIImage> createGeneratedImage(String channel, String topic, MultipartFile image) {
        final String key = AIImage.PREFIX_PATH + ImagePathGenerator.next(image.getOriginalFilename());
        try {
            ossAdapter.putObject(key, image.getInputStream());
        } catch (OSSException ose) {
            log.warn("Failed to put object, due to oss exception. requestId : {}, fileName : {}", ose.getRequestId(), image.getOriginalFilename(), ose);
            throw new RuntimeException(ose);
        } catch (ClientException ce) {
            log.warn("Failed to put object, due to client exception. requestId : {}, fileName : {}", ce.getRequestId(), image.getOriginalFilename(), ce);
            throw new RuntimeException(ce);
        } catch (Exception e) {
            log.warn("Failed to put object, fileName : {}", image.getOriginalFilename(), e);
            throw new RuntimeException(e);
        }

        return save(channel, topic, key);
    }

    @Override
    public void createGeneratedImage(AddAIImageRequest request, MultipartFile image) {
        String channelType = request.getChannel();
        String topicType = request.getTopic();
        String filename = image.getOriginalFilename();
        final String key = AIImage.PREFIX_PATH + ImagePathGenerator.next(filename);
        try {
            ossAdapter.putObject(key, image.getInputStream());
        } catch (OSSException ose) {
            log.warn("Failed to put object, due to oss exception. requestId : {}, fileName : {}", ose.getRequestId(), filename, ose);
            throw new RuntimeException(ose);
        } catch (ClientException ce) {
            log.warn("Failed to put object, due to client exception. requestId : {}, fileName : {}", ce.getRequestId(), filename, ce);
            throw new RuntimeException(ce);
        } catch (Exception e) {
            log.warn("Failed to put object, fileName : {}", filename, e);
            throw new RuntimeException(e);
        }


        //保存到数据库
        AIImage build = AIImage.builder()
                .channelType(channelType)
                .topicType(topicType)
                .imagePath(key)
                .prompt(request.getPrompt())
                .name(filename.substring(0,filename.indexOf(".")))
                .negativePrompt(request.getNegativePrompt())
                .sampler(request.getSampler())
                .inferenceSteps(request.getInferenceSteps())
                .cfgScale(request.getSfgScale())
                .modelName(request.getModelName())
//                .createdBy("ADMIN")
//                .updatedBy("ADMIN")
                .build();
        aiImageRepository.save(build);

    }

    private List<AIImage> save(String channelType, String topicType, String keys) {
        List<AIImage> saveList = new LinkedList<>();
     saveList.add(AIImage.builder()
            .channelType(channelType)
            .topicType(topicType)
            .imagePath(keys)
//            .createdBy("ADMIN")
//            .updatedBy("ADMIN")
            .build());
        return aiImageRepository.saveAll(saveList);
    }

    @Override
    public JSONObject crop(cropReq cropReq, MultipartFile file) throws Exception {
        final String key = AIImage.PREFIX_PATH + ImagePathGenerator.next(file.getOriginalFilename());
        ossAdapter.putObject(key, file.getInputStream());
        JSONObject crop = faceChainAdapter.crop(key, new Integer[]{cropReq.getWidth(), cropReq.getHeight()});
        if(crop.getInteger("code") == -2) {
            throw new ServiceException("未检测到人脸，请确保人脸清晰、端正");
        }
        if(crop.getInteger("code") != 0){
            throw new ServiceException("裁减失败");
        }

        return crop.getJSONObject("data");
    }

}
